#coding=utf-8
import cv2
import numpy as np
import os
import matplotlib.pyplot as plt
from PIL import Image
import pytesseract

def matchWordTemplate(gray_im, Img_word):
    wordPos = []  # 满足条件字体位置
    res = cv2.matchTemplate(gray_im, Img_word, cv2.TM_CCOEFF_NORMED)
    threshold = 0.7
    loc = np.where(res >= threshold)
    # print loc
    # print zip(*loc[::-1])
    for pt in zip(*loc[::-1]):
        # if (pt[0] > int(gray_im.shape[0] / 3)):
        wordPos.append(pt)
            # cv2.rectangle(im, pt, (pt[0] + Img_word.shape[1], pt[1] + Img_word.shape[0]), (0, 0, 255), 2)
    if len(wordPos) == 0:
        min_val, max_val, min_loc, max_loc = cv2.minMaxLoc(res)

        # if (max_loc > 0.5):# & (max_loc[0] > int(gray_im.shape[0] / 3)):  # 判断位置，只有高于图片1/4的位置被识别
        if max_val > 0.4:
            wordPos.append(max_loc)
            # cv2.rectangle(im, (max_loc[0], max_loc[1]), (max_loc[0] + Img_word.shape[1], max_loc[1] + Img_word.shape[0]), (255, 0, 0),2)  # 画出边界框（正的矩形）
    return wordPos


def getMatchWordTemplateSimilarity(gray_im, Img_word):
    # 获取匹配的相似度
    res = cv2.matchTemplate(gray_im, Img_word, cv2.TM_CCOEFF_NORMED)
    min_val, max_val, min_loc, max_loc = cv2.minMaxLoc(res)
    return max_val

def getBestScale(gray_im):  #
    # 获取最佳放缩倍数
    H, W = gray_im.shape[:2]  # 获取图像高度和宽度
    scaleSet = np.linspace(0.35, 1.5, 8)  # 缩放集合 等差数列，间隔为8
    scaleSimSet = []  # 缩放相似性集合
    for scale in scaleSet:  # np.arange(0.35,1.5,0.25):
        Img_scale_im = cv2.resize(gray_im, (int(W * scale), int(H * scale)))  # 重新放缩
        simSet = []  # 存储本次图片放缩的拟合度集合
        for png in os.listdir('templates'):
            Img_word = cv2.imread("templates/" + png, 0)  # 读取字体模板
            sim = getMatchWordTemplateSimilarity(Img_scale_im, Img_word) #获得相似度
            if sim > 0.5:  # 取相似性大于0.5
                simSet.append(sim)
        # print(scale, simSet)
        if (len(simSet) > 0):
            scaleSimSet.append(np.mean(simSet))
        else:
            scaleSimSet.append(0)
    # print scaleSimSet
    scale = scaleSet[np.argmax(scaleSimSet)]  # 获取最佳放缩倍数
    return H, W, scale


def getKeyWordInfo(gray_im, im, flag=1):
    # 获取关键字眼信息
    # keyWordInfo:numpy.array,size=(,4),存储所有关键字的位置信息，[x,y,delta_x,delta_y]
    # x:关键字左上角宽度坐标，y关键字左上角高度坐标，delta_x,关键字宽度，delta_y，关键字高度

    # keyWordInfoWordAndPosition，dict(),存储每个关键字的位置信息，key为关键字
    # 每个key里面内容为numpy.array,size=(,4),存储所有关键字的位置信息，[x,y,delta_x,delta_y]
    # x:关键字左上角宽度坐标，y关键字左上角高度坐标，delta_x,关键字宽度，delta_y，关键字高度
    keyWordInfo = []
    keyWordInfoWordAndPosition = dict()
    for png in os.listdir('templates'):
        Img_word = cv2.imread("templates/" + png, 0)  # 读取字模板
        # print("template2/" + png)
        wordPos = matchWordTemplate(gray_im, Img_word)
        keyWordInfoWordAndPosition[png] = []
        if len(wordPos) > 0:
            for pos in wordPos:
                keyWordInfo.append([pos[0], pos[1], Img_word.shape[1], Img_word.shape[0]])
                keyWordInfoWordAndPosition[png].append([pos[0], pos[1], Img_word.shape[1], Img_word.shape[0]])
    if len(keyWordInfo) > 0:
        if len(keyWordInfo) > 1:
            keyWordInfo = sorted(keyWordInfo, key=lambda x: (x[0], x[1]))
            # print keyWordInfo
            keyWordInfo = np.array(keyWordInfo)
            temp = np.diff(keyWordInfo, axis=0)
            judegeX = np.hstack([1000, np.abs(temp[:, 0])])
            judegeY = np.hstack([1000, np.abs(temp[:, 1])])
            keyWordInfo = keyWordInfo[(judegeX > 5) | (judegeY > 5), :]
        else:
            keyWordInfo = np.array(keyWordInfo)
        # if flag == 1:
        #     for i in range(keyWordInfo.shape[0]):
        #         cv2.rectangle(im, (keyWordInfo[i, 0], keyWordInfo[i, 1]),
        #                       (keyWordInfo[i, 0] + keyWordInfo[i, 2], keyWordInfo[i, 1] + keyWordInfo[i, 3]),
        #                       (0, 0, 255), 10)
    # 判断
    keyWordInfoRowNum = keyWordInfo.shape[0]
    for png in os.listdir('templates'):
        thisPngKeyWord = keyWordInfoWordAndPosition[png]
        thisPngKeyWord = np.array(thisPngKeyWord)
        getKeyWordList = []
        for i in range(thisPngKeyWord.shape[0]):
            ith_thisPngKeyWord = np.tile(thisPngKeyWord[i,:],(keyWordInfoRowNum ,1))
            getKeyWordList.append(np.any(np.sum(ith_thisPngKeyWord-keyWordInfo,axis=1)==0))
        keyWordInfoWordAndPosition[png] = thisPngKeyWord[getKeyWordList,:]
    return keyWordInfo,keyWordInfoWordAndPosition


def getWordArea(gray_im):
    # kernel = cv2.getStructuringElement(cv2.MORPH_RECT, (7,7))
    kernel = cv2.getStructuringElement(cv2.MORPH_CROSS, (15, 15))
    gray = cv2.morphologyEx(gray_im, cv2.MORPH_OPEN, kernel)
    ret, thresh = cv2.threshold(gray, 127, 255, 0)
    thresh = 255 - thresh
    images, contours, hierarchy = cv2.findContours(thresh, cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE)  # 对每一个连贯的形状画出边框
    cSet = []
    for c in contours:
        x, y, w, h = cv2.boundingRect(c)
        cSet.append([x, y, w, h])
    cSet = sorted(cSet, key=lambda x: (x[2], x[3]), reverse=True)
    cSet = np.array(cSet)
    findElementArea = []
    curElement = cSet[0, :]
    cSet = cSet[1:, :]
    findElementArea.append(list(curElement))
    while len(cSet) > 0:
        judge1 = (cSet[:, 0] > curElement[0]) & (cSet[:, 1] > curElement[1])
        judge2 = ((cSet[:, 0] + cSet[:, 2]) <= (curElement[0] + curElement[2])) & (
                    (cSet[:, 1] + cSet[:, 3]) <= (curElement[1] + curElement[3]))
        judge = judge1 & judge2
        cSet = cSet[~judge, :]
        curElement = cSet[0, :]
        cSet = cSet[1:, :]
        findElementArea.append(list(curElement))
        # print(cSet.shape)
    # for area in findElementArea:
    #     cv2.rectangle(im, (area[0], area[1]), (area[0]+area[2], area[1]+area[3]), (255, 255, 0), 2)
    return findElementArea

def gamma(im, k): #gamma变换
    em=im.astype("float32")
    # height,width=im.shape[:2]
    fm=np.zeros(em.shape, dtype=np.float32)
    em=em**k
    for i in range(3):
        a = np.zeros(em.shape[:2], dtype=np.float32)
        cv2.normalize(em[:,:,i],a,0,255,cv2.NORM_MINMAX)
        fm[:,:,i]=a
    return fm.astype("uint8")


def find_retangles(gray, scale): #画出所有合适的框框
    gray = cv2.blur(gray, (3, 3))
    median = np.median(gray)
    yuzhi = 100
    tangles = 0
    save = 0
    while yuzhi < 200:
        ret, thresh = cv2.threshold(gray, yuzhi, 255, cv2.THRESH_BINARY)
        # thresh=cv2.medianBlur(thresh, 3)
        points = []
        image, contours, hier = cv2.findContours(thresh, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
        for c in contours:
            x, y, w, h = cv2.boundingRect(c)
            if w > h * 2 and w > 100*scale and h>50*scale:
                # cv2.rectangle(im, (x,y), (x+w,y+h), (255,0,0), 3) #画出所有的小框框 
                points.append([x, y, w, h])
        if len(points) > tangles:
            tangles = len(points)
            save = yuzhi
        yuzhi += 5

    # print(save)
    ret, thresh = cv2.threshold(gray, save, 255, cv2.THRESH_BINARY)
    points = []
    image, contours, hier = cv2.findContours(thresh, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
    for c in contours:
        x, y, w, h = cv2.boundingRect(c)
        if w > h * 2 and w > 100*scale and h > 50*scale:
            # cv2.rectangle(im, (x,y), (x+w,y+h), (255,0,0), 2) #
            points.append([x, y, w, h])
            # image=thresh[y:y+h, x:x+w]
    return points

im=cv2.imread("shouju.jpg")
gray=im[:,:,0]

# print rectangles
# for rectangle in rectangles:
#     x,y,w,h=rectangle
#     cv2.rectangle(im, (x, y), (x + w, y + h), (255, 0, 0), 2)
H,W,scale=getBestScale(gray)
gray=cv2.resize(gray, (int(W * scale), int(H * scale)))
im = cv2.resize(im, (int(W * scale), int(H * scale)))
rectangles=np.array(find_retangles(gray, scale))
for rectangle in rectangles:
    x,y,w,h=rectangle
    cv2.rectangle(im, (x, y), (x + w, y + h), (0, 0, 0), 5) #### 画出所有黑色的框
copyone=rectangles.copy()
_, keyWordInfoWordAndPosition = getKeyWordInfo(gray, im)
# print('aaa:',keyWordInfoWordAndPosition) #获得所有包括相似的关键字位置信息

### 模板匹配会有两个相似的位置的，删除一个相似的位置
for key in keyWordInfoWordAndPosition.keys(): 
    temp=keyWordInfoWordAndPosition[key]
    # print temp
    indextodelete=[]
    uniquedata=[]
    if len(temp)>1: #如果匹配到多个位置，则需要判断是否使相似的位置
        for i in range(len(temp)-1):
            for j in range(i+1, len(temp)):
                if abs(temp[j][0]-temp[i][0])<5:
                    indextodelete.append(j)
    if len(indextodelete)>0: #如果有相似的位置，则将不在indextodelete的位置添加到uniquedata中。间接删除了相似的位置
        for i in range(len(temp)):
            if i not in indextodelete:
                uniquedata.append(temp[i])
        keyWordInfoWordAndPosition[key]=uniquedata
for key in keyWordInfoWordAndPosition:
    temp=keyWordInfoWordAndPosition[key]
    for word in temp:
        cv2.rectangle(im, (word[0],word[1]), (word[0]+word[2], word[1]+word[3]), (0,0,255), 5) ###画出矩形，需要给出左上角与右下角的坐标

print(keyWordInfoWordAndPosition)


if len(keyWordInfoWordAndPosition["templates_ming.png"])>0: #姓名
    hight, width = im.shape[:2]
    word = keyWordInfoWordAndPosition["templates_ming.png"][0] #取出第一个带有名字的框框
    temp=[]
    # print(word)
    for rectangle in rectangles: #rectangles为所有的框框
        # 如果框框的近原点的y坐标小于带有“名”字的框框 且 远离原点的y坐标大于“名”字的y坐标 且 框框的最大横坐标要小于图片宽度的一半
        if rectangle[1] < word[1] and rectangle[1]+rectangle[3]>word[1]+word[3] and rectangle[0]+rectangle[2] < width/2:
            temp.append(rectangle)

            # x,y,w,h=rectangle
    temp = np.array(temp)
    minx = min(temp[:,0])
    miny = min(temp[:,1])
    maxx = max(temp[:,0]+temp[:,2])
    maxy = max(temp[:,1]+temp[:,3])

    cv2.rectangle(im, (minx, miny),(maxx, maxy), (255, 0, 0), 5)

if len(keyWordInfoWordAndPosition["template_jin.png"])>0: #金额
    jinword = keyWordInfoWordAndPosition["template_jin.png"]
    jinword = np.array(jinword)
    jinword = jinword[jinword[:,1].argsort()]
    jinword = jinword[0]
    print(jinword)
    if len(keyWordInfoWordAndPosition["template_fei.png"])>0:
        rectangles = rectangles[rectangles[:,1].argsort()]
        border = rectangles[-1][1]
        feiword = keyWordInfoWordAndPosition["template_fei.png"]
        feiword = np.array(feiword)
        feiword = feiword[feiword[:,1] < border]
        feiword = feiword[feiword[:,1].argsort()]
        firstfeiword=feiword[0]
        lastfeiword = feiword[-1]
        save=[]
        for rectangle in rectangles:
            if rectangle[1] > firstfeiword[1]+firstfeiword[3] and rectangle[1]+rectangle[3] < lastfeiword[1]:
                save.append(rectangle)
                # x, y, w, h = rectangle
                # cv2.rectangle(im, (x, y), (x + w, y + h), (0, 255, 0), 5)
        save=np.array(save)
        h = int(np.mean(save[:,3]))
        minx = min(save[:,0])
        miny = min(save[:,1])
        maxx = max(save[:,0]+save[:,2])
        maxy = max(save[:,1]+save[:,3])
        if (maxy-miny)*1./h<3.5:
            cv2.rectangle(im, (minx, miny), (maxx, maxy), (255,0,0), 10)
        else:
            cv2.rectangle(im, (minx, miny+h), (maxx, maxy), (255,0,0), 10)
        temp = []
        for rectangle in save:
            if rectangle[0] < lastfeiword[0] and rectangle[0]+rectangle[2] > lastfeiword[0]+lastfeiword[2]:
                temp.append(rectangle)
                x,y,w,h=rectangle
                # cv2.rectangle(im, (x, y), (x + w, y + h), (0, 255, 0), 5)
        temp = np.array(temp)
        temp = temp[temp[:,1].argsort()]
        temp = temp[-1]
        x,y,w,h=temp
        y=y+2*h
        cv2.rectangle(im, (x, y), (x + 2*w, y + h), (255,0,0), 5)

plt.figure(1), plt.imshow(cv2.cvtColor(im, cv2.COLOR_BGR2RGB))
# plt.figure(1), plt.imshow(gray, cmap="gray")
plt.show()
